package com.sardine.base.mybatis.router;


import com.sardine.base.exception.SardineException;
import com.sardine.base.utils.JsonUtils;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.Node;
import org.dom4j.io.SAXReader;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

/**
 * 北京京东世纪贸易有限公司<br>
 * Created with IntelliJ IDEA.
 * Date:2015/11/17
 * Time:8:59
 * 解析 router xml 文件得到 路由信息
 * @author daifeng<br>
 *         daifeng@jd.com
 * @since JDK 1.6 <br>
 * Copyright (c) 2015 JD System Incorporated All Rights Reserved.
 */
public class RouterXmlFactoryBean {
    private static final Logger logger = LoggerFactory.getLogger(RouterXmlFactoryBean.class);

    private volatile static  RouterXmlFactoryBean instance=null;
//    private volatile Map<String,Router> routerMap=new ConcurrentHashMap<String, Router>();
    private volatile Map<String,Router> routerMap=new HashMap<String, Router>();

    private static final String RULE="rule";
    private static final String NAMESPACE="namespace";
    private static final String CLAZZ="shardingExpressionClass";
    private static final String PLACEHOLDERCHAR="placeholderChar";


    private RouterXmlFactoryBean(String routerXmlPath) {
        try {
            InputStream resourceAsStream = RouterXmlFactoryBean.class.getClassLoader().getResourceAsStream(routerXmlPath);
            SAXReader reader=new SAXReader();
            Document document=reader.read(resourceAsStream);
            Element rootElement = document.getRootElement();
            treeWalkRules(rootElement);
            logger.info("分表路由信息：{}", JsonUtils.toJson(routerMap));
            resourceAsStream.close();
        } catch (IOException e) {
            logger.error("获取分表路由xml文件异常", e);
            throw new SardineException("获取分表路由xml文件异常");
        }catch (DocumentException e) {
            logger.error("Dom4J解析分表路由xml文件异常", e);
            throw new SardineException("解析分表路由xml文件异常");
        }
    }

    /***
     * 递归方式解析---遍历节点
     *
     * @param root
     */
    private void treeWalkRules(Element root){
        for(Iterator i=root.nodeIterator();i.hasNext();){
            Node node=(Node)i.next();
            if(node instanceof Element){
                String name = node.getName();
                if(RULE.equals(name)){
                    Router router = new Router();
                    treeWalkRule((Element) node, router);
                    routerMap.put(router.getNamespace(),router);
                }else {
                    logger.warn("分表路由xml文件，存在非法的节点，节点名称：{}", name);
                }
            }
        }
    }
    /***
     * 递归方式解析---遍历节点
     *
     * @param root
     */
    private void treeWalkRule(Element root, Router router){
        for(Iterator i=root.nodeIterator();i.hasNext();){
            Node node=(Node)i.next();
            if(node instanceof Element){
                String name = node.getName();
                boolean bool=false;
                String text = node.getText().trim();
                if(NAMESPACE.equals(name)){
                    router.setNamespace(text);
                    bool=true;
                }
                if(CLAZZ.equals(name)){
                    try {
                        Class classType = Class.forName(text);
                        RuleExpression obj = (RuleExpression)classType.newInstance();
                        router.setClazz(obj);
                        bool=true;
                    }catch (ClassNotFoundException e) {
                        logger.warn("分表路由xml文件，rule 节点shardingExpressionClass，配置类不存在：{}", text);
                    }catch (InstantiationException e) {
                        logger.warn("分表路由xml文件，rule 节点shardingExpressionClass，构造异常：{}", text);
                    } catch (IllegalAccessException e) {
                        logger.warn("分表路由xml文件，rule 节点shardingExpressionClass，构造参数异常：{}", text);
                    }
                }
                if(PLACEHOLDERCHAR.equals(name)){
                    router.setPlaceholderChar(text);
                    bool=true;
                }
                if(!bool){
                    logger.warn("分表路由xml文件，rule 节点下存在非法的节点，节点名称：{}", name);
                }
            }
        }
    }
    /**
     * 构建一个路由工厂
     * @param routerXmlPath
     * @return
     */
    public static RouterXmlFactoryBean getInstance(String routerXmlPath){
        if (instance == null) {
            synchronized (RouterXmlFactoryBean.class) {
                if (instance == null) {
                    instance = new RouterXmlFactoryBean(routerXmlPath);
                }
            }
        }
        return instance;
    }

    /**
     * 根据命名空间查询 分表路由
     * @param namespace
     * @return
     */
    public Router getRouter(String namespace){
       return routerMap.get(namespace);
    }


    /**
     * 北京京东世纪贸易有限公司<br>
     * Created with IntelliJ IDEA.
     * Date:2015/11/17
     * Time:8:53
     * 解析xml文件。得到分页的信息
     * @author daifeng<br>
     *         daifeng@jd.com
     * @since JDK 1.6 <br>
     * Copyright (c) 2015 JD System Incorporated All Rights Reserved.
     */
    public class Router {
        //算法类
        private RuleExpression clazz;
        //MyBatis命名空间
        private String namespace;
        //占位符字符
        private String placeholderChar;

        public RuleExpression getClazz() {
            return clazz;
        }

        private void setClazz(RuleExpression clazz) {
            this.clazz = clazz;
        }

        public String getNamespace() {
            return namespace;
        }

        private void setNamespace(String namespace) {
            this.namespace = namespace;
        }

        public String getPlaceholderChar() {
            return placeholderChar;
        }

        private void setPlaceholderChar(String placeholderChar) {
            this.placeholderChar = placeholderChar;
        }
    }

}
